package com.run2code.listener;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.run2code.domain.Salaries;
import com.run2code.service.SalariesService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


/**
 * 薪资导入-监听器
 *
 * @author 第七人格
 * @date 2023/09/28
 */
public class SalariesListener implements ReadListener<Salaries> {

    private SalariesService salariesService;

    /**
     * 通过构造方法注入的方式，我们得到的SalariesService其实就是Spring的代理对象
     *
     * @param salariesService
     */
    public SalariesListener(SalariesService salariesService) {
        this.salariesService = salariesService;
    }

    private static final Log logger = LogFactory.getLog(SalariesListener.class);

    /**
     * 因为每一个SalariesListener都是我们自己new出来的，所以不存在并发安全问题，替换成ArrayList即可
     */
    ArrayList<Salaries> salariesList = new ArrayList<>();

    private final ExecutorService executorService = Executors.newFixedThreadPool(20);

    private static final int batchSize = 10000;

    /**
     * 处理数据的回调
     *
     * @param data
     * @param context
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void invoke(Salaries data, AnalysisContext context) {
        salariesList.add(data);
        if (salariesList.size() >= batchSize) {
            saveBatch();
        }
    }

    public void saveBatch() {
        if (!salariesList.isEmpty()) {
            // 先从副本中copy一份数据出来
            ArrayList<Salaries> salaries = (ArrayList<Salaries>) salariesList.clone();
            // 并发执行
            executorService.execute(new SaveTask(salaries, salariesService));
            // 执行完了之后需要清空数据，方便下次使用
            salariesList.clear();
        }
    }

    static class SaveTask implements Runnable {

        private List<Salaries> salariesList;
        private SalariesService salariesService;

        public SaveTask(List<Salaries> salariesList, SalariesService salariesService) {
            this.salariesList = salariesList;
            this.salariesService = salariesService;
        }

        @Override
        public void run() {
            salariesService.saveBatch(salariesList);
        }
    }

    /**
     * 数据处理完的回调
     *
     * @param context
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void doAfterAllAnalysed(AnalysisContext context) {
        if (!salariesList.isEmpty()) {
            salariesService.saveBatch(salariesList);
        }
        logger.info("所有数据处理完毕");
    }
}
